<template>
    <div :class="prefixCls" :id="RichTextId" :style="{ width: containerWidth }">
        <Toolbar :class="prefixCls + '-toolbar'"
            :editor="editorRef"
            :defaultConfig="toolbarConfig"
            :mode="mode"
        />
        <Editor :class="prefixCls + '-editor'" :style="{ height: containerHeight }"
            v-model="valueHtml" 
            :defaultConfig="editorConfig" 
            :mode="mode" 
            @onCreated="handleCreated"
            @onChange="handleChange" 
        />
    </div>
</template>

<script lang="ts" setup>
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { useDesign } from '@/components/form/index';
import { isNumber, isObject } from '@/utils/is';

interface tinymceProps {
    value?: string | any,
    height?: number | string,
    width?: number | string,
    disabled?: boolean,
}
const props = withDefaults(defineProps<tinymceProps>(), {
    value: '',
    height: 500,
    width: 'auto',
    disabled: false,
});
const emit = defineEmits(['change']);

const { prefixCls } = useDesign('wangeditor-container');

const RichTextId = ref<string>(Math.floor(Math.random() * 900) + 1000); // id值

const containerWidth = computed(() => {
    const width = props.width;
    if (isNumber(width)) return `${width}px`;
    return width;
});
const containerHeight = computed(() => {
    const height = props.height;
    if (isNumber(height)) return `${height}px`;
    return height;
});

// 编辑器内容
const valueHtml = ref<any>();
watchEffect(() => {
    if(!isObject(props.value)){
        valueHtml.value = props.value;
    }
});

const mode = ref<string>('default'); // 或 'simple'
// 工具栏配置
const toolbarConfig = ref<Recordable>({});

// 编辑器配置
let editorConfig = ref<Recordable>({ placeholder: '请输入内容...', MENU_CONF: {} });

type InsertFnType = (url: string, alt: string, href: string) => void;
// 上传图片配置
editorConfig.value.MENU_CONF['uploadImage'] = ref<Recordable>({

    // 单个文件的最大体积限制，默认为 2M
    maxFileSize: 10 * 1024 * 1024, // 文件限制10M

    // 最多可上传几个文件，默认为 100
    maxNumberOfFiles: 10,

    // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
    allowedFileTypes: ['image/*'],

    // 自定义上传
    async customUpload(file: File, insertFn: InsertFnType) {  // TS 语法
        // file 即选中的文件
        // console.log(file);
        // 自己实现上传，并得到图片 url alt href
        const reader = new FileReader(); //实例化文件读取对象
        reader.readAsDataURL(file); //将文件读取为 DataURL,也就是base64编码
        reader.onload = (e: any)=> { //文件读取成功完成时触发
            const dataURL = e.target.result; //获得文件读取成功后的DataURL,也就是base64编码
            // console.log(dataURL);
            insertFn(dataURL, '', dataURL); // 最后插入图片
        };
    },

    // 上传错误，或者触发 timeout 超时
    onError(file: Recordable, err: Recordable, res: Recordable) {
        console.error('上传失败：onError', file, err, res);
    },
});

// 上传视频的配置
editorConfig.value.MENU_CONF['uploadVideo'] = ref<object>({
    // 单个文件的最大体积限制，默认为 10M
    maxFileSize: 5 * 1024 * 1024, // 5M
    // 最多可上传几个文件，默认为 5
    maxNumberOfFiles: 3,

    // 选择文件时的类型限制，默认为 ['video/*'] 。如不想限制，则设置为 []
    allowedFileTypes: ['video/*'],
    // 自定义上传
    async customUpload(file: File, insertFn: InsertFnType) {  // TS 语法
    // async customUpload(file, insertFn) {                   // JS 语法
        // file 即选中的文件
        // console.log(file);
        // 自己实现上传，并得到视频 url poster
        const reader = new FileReader(); //实例化文件读取对象
        reader.readAsDataURL(file); //将文件读取为 DataURL,也就是base64编码
        reader.onload = (e: any)=> { //文件读取成功完成时触发
            const dataURL = e.target.result; //获得文件读取成功后的DataURL,也就是base64编码
            // console.log(dataURL);
            insertFn(dataURL, '', '');// 最后插入视频
        };
    },

    // 上传错误，或者触发 timeout 超时
    onError(file: File, err: any, res: any) {  // TS 语法
        console.log(`${file.name} 上传出错`, err, res);
    },
});

const editorRef = shallowRef(); // 编辑器实例，必须用 shallowRef
const handleCreated = (editor: any) => {
    // console.log(editor);
    emit('change', editor);
    editorRef.value = editor; // 记录 editor 实例，重要！
};

// change事件
const handleChange = (editor: { getHtml: () => any; }) => {
    // console.log('change:', editor.getHtml());
    const value = editor?.getHtml();
    emit('change', value);
    editorRef.value = editor; // 记录 editor 实例，重要！
};

const clear = () =>{
    const editor = editorRef.value;
    editor.setHtml(''); // 清空内容
};

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
    const editor = editorRef.value;
    if (editor == null) return;
    editor.destroy();
});

defineExpose({ clear });
</script>
<style lang="less">
@namespace: 'dly';
@prefix-cls: ~'@{namespace}-wangeditor-container';

.@{prefix-cls} {
    border: 1px solid #d9d9d9;

    &-toolbar {
        border-bottom: 1px solid #ccc
    }
    &-editor {
        overflow-y: hidden;
    }
}

.w-e-full-screen-container {
    z-index: 9999;
}
</style>